package com.dayu.finecomm.decoder;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;

import java.util.List;

import org.apache.commons.lang3.tuple.Pair;

import com.dayu.finecomm.protocol.ProtocolPacket;
import com.dayu.finecomm.protocol.Protocols;
import com.dayu.finecomm.protocol.SpecialCareChannelInboundAdapter;
import com.dayu.finecomm.protocol.codec.ProtocolDecoder;
import com.dayu.finecomm.protocol.pojo.TPacket;
import com.dayu.finecomm.utils.Helpers;

/**
 * udp decoder 详见父类
 * 
 * @author Chenjiawei
 * 
 *         2017年6月9日
 */
public class HdUdpDecoder extends
		SpecialCareChannelInboundAdapter<DatagramPacket> {

	String prefix;
	List<ProtocolDecoder<TPacket>> protocols;

	public HdUdpDecoder(String prefix, List<ProtocolDecoder<TPacket>> protocols) {

		this.prefix = prefix;
		this.protocols = protocols;
	}

	@Override
	public void channelRead0(ChannelHandlerContext ctx, DatagramPacket dpacket)
			throws Exception {

		ByteBuf msg = dpacket.content();

		try {

			ByteBuf in = msg;

			if (in.readableBytes() < 5) {

				ctx.fireChannelRead(msg);
				return;
			}

			boolean valid = false;
			ProtocolDecoder<TPacket> cur = null;

			Pair<ProtocolDecoder<TPacket>, Pair<Integer, TPacket>> pair = Protocols
					.decode(protocols, in);

			if (pair != null) {

				cur = pair.getLeft();

				int length = pair.getRight().getLeft();
				TPacket s = pair.getRight().getRight();
				s.address = dpacket.sender();
				s.in = Helpers.bytesToHex(in);

				valid = true;
				s.prefix = prefix;

				ctx.fireChannelRead(s);
				ctx.fireChannelRead(new ProtocolPacket(in.slice(0, length),
						true));

			}

			if (!valid || !timing(ctx, dpacket, cur)) {

				// 【回包】 无论如何都应该回包，除非收到的报文本身以@222为前缀
				if (!(in.readableBytes() == 4 && in.getUnsignedInt(0) == 0x40323232)) {
					if (cur == null || cur.needEcho()) {
						ctx.writeAndFlush(new DatagramPacket(Unpooled
								.copiedBuffer("@222".getBytes()), dpacket
								.sender()));
					}
				}
			}

			if (!valid) {
				ctx.fireChannelRead(msg);
			}

		} finally {

			msg.release();
		}
	}

	/**
	 * 校时
	 */
	private boolean timing(ChannelHandlerContext ctx, DatagramPacket dpacket,
			ProtocolDecoder<?> cur) {

		if (cur == null)
			return false;

		boolean needTiming = com.dayu.finecomm.utils.Helpers.needTiming();

		if (needTiming) {

			Object timing = cur.timing();

			if (timing != null) {
				ctx.writeAndFlush(new DatagramPacket(Unpooled
						.copiedBuffer(((String) timing).getBytes()), dpacket
						.sender()));
			}
		}

		return needTiming;
	}
}
